/*
-----------------------------------------------------------------------------
This source file is part of DIVA
The project of Engineering Lab, dept. of CSIE, NTNU.

Copyright (c) 2000-2006 The Engineering Lab, dept. of CSIE, NTNU.
-----------------------------------------------------------------------------
Filename:    DIVA_VM.h
Description: we defined several basic abstract actions that all VMs should implement,like:pick,select,drag....


目前暫定: 
ogreVM, DIVA_AbstractVM, 以及DIVA_VM 都放在vm的資料夾底下
primitive type 的vm,其結尾就以 ptvm結尾，例：ball_int_ptvm.h
composite type 的vm,其結尾就以 cpvm結尾，例：Tree_Node_cpvm.h
reference type 的vm,其結尾就以 rtvm結尾，例：shing_ball_rtvm.h
layout type  的vm,其結尾就以 lyvm結尾，例：  tree_lyvm.h

update history	8/29	增加DIVA_VM(xParameterPack xpp)目的是為每一個vm相同的
port attribute作連結，提供給DIVA_VM的child VM呼叫

修改日期 : 08/10/20
修改者 : hyt
新增method :
     (1) VL_createEntity
	 (2) VL_regBoundingBox
	 (3) VL_arrangeVMs
	 (4) VL_computeMaxBoundingsize
	 (5) VL_computeMinBoundingsize
	 (6) VL_setVMsPosition
	 (7) VL_minimizeVMsize
	 (8) VL_propagateMouseEvent
	 (9) VL_setEntityColor
	 (10) VL_getVMMovableObjectTable
	 (11) VL_createTextNode
	 (12) VL_createVMtext
	 (13) VL_updateText

-----------------------------------------------------------------------------
*/
#ifndef _DIVA_VM_H_
#define _DIVA_VM_H_

#include "DIVA_AbstractVM.h"
#include "OgreVM.h"
#include "MovableText.h" // hyt 08/10/20

// use defined macro to control testing instructions
#include "DIVA_Application.h"

using namespace std;

class xParameterPack;
class DIVA_VM: public DIVA_AbstractVM, public OgreVM {
public:
	//hyt 08/10/20
	enum Coordinate_axis {X_Max,Y_Max,Z_Max,X_Min,Y_Min,Z_Min,X_Positive_Stretch,Y_Positive_Stretch,Z_Positive_Stretch,DO_NOTHING};
	// hyt 08/10/20
	enum TextPosition {TOP,BOTTOM,LEFT,RIGHT,FRONT,BACK,CENTER};
	enum Prohibit	{ SKIP_NAME, SKIP_POSITION, SKIP_SIZE, SKIP_SCALE, SKIP_COLOR, SKIP_ROTATION,SKIP_TRANS, SKIP_QUATERNION, SKIP_CLICKMSG};
	static const int RC = 2 ; // the offset of _vm_rx ;
	static const int SIZE = RC+3 ; // the offset of _vm_sizex 
	static const int SCALE =SIZE+3 ;// the offset of _vm_sizexscale 
	static const int RGB = SCALE + 3 ; // the offset of _vm_r ;
	static const int TRANS = RGB + 3 ; // the offset of _vm_transparency ;
	static const int ROTATE = TRANS+1 ; // the offset of _vm_yaw ; 
	static const int QUAT = ROTATE + 3 ; // the offset of _vm_quat 
	static const int CLICKMSG = QUAT + 1 ;
	static const int INIT_VM_SIZE = 100 ;

	static const int INIT_YAW = 0 ;
	static const int INIT_PITCH = 0 ;
	static const int INIT_ROLL = 0 ;
	

	static const int TEXT_HEIGHT = 30 ;
	//----------------------------------------------
	// The overridden methods in OgreVM
	//----------------------------------------------
	virtual void setPosition(Ogre::Vector3 pos);	
	virtual void setPosition(Ogre::Real x,Ogre::Real y,Ogre::Real z) { setPosition(Ogre::Vector3(x,y,z)); }	

	//----------------------------------------------
	// The overridden methods in DIVA_AbstractVM 
	//-----------------------------------------------
	virtual void VMPicked(Ogre::Real x,Ogre::Real y,Ogre::Real z);
	virtual void VMSelected(Ogre::Real x,Ogre::Real y,Ogre::Real z) { assert(false) ;} 
	/** (sceenx, screeny) are the click pos of mouse, where center is (0,0)
	    (absx,absy,absz) are the interpolate positions of the 3d world coordinates. */
	virtual void VMDragged(Ogre::Real screenx, Ogre::Real screeny, 
		                   Ogre::Real absx,Ogre::Real absy,Ogre::Real absz) ;
	virtual void VMValueUpdated() ; // override the one from DIVA_VM
	virtual void VMSetVisible(bool vis);


	//------------------------------------------------
	// Methods originates from this class
	//------------------------------------------------
	virtual void set_movable(bool m) { _movable = m ; }
	virtual bool get_movable() { return _movable ; }
	virtual bool get_visible() { return _visible ; }

	string get_vm_name() { return _name ; }
	int get_vm_name_position() { return _vm_name_position ; }
	float* get_vm_rx() { return &(_vm_rx_val) ;}
	float* get_vm_ry() { return &(_vm_ry_val) ; }
	float* get_vm_rz() { return &(_vm_rz_val) ; }
	float* get_vm_sizex() { return &(_vm_sizex_val) ; }
	float* get_vm_sizey() { return &(_vm_sizey_val) ; }
	float* get_vm_sizez() { return &(_vm_sizez_val) ; }
	double* get_vm_sizexscale() { return &(_vm_sizexscale_val); }
	double* get_vm_sizeyscale() { return &(_vm_sizeyscale_val); }
	double* get_vm_sizezscale() { return &(_vm_sizezscale_val); }
	double * get_vm_r() { return &(_vm_r_val) ; }  
	double * get_vm_g() { return &(_vm_g_val) ; }
	double * get_vm_b() { return &(_vm_b_val) ; }
	double * get_vm_transparency() {return &(_vm_transparency_val);}

	int * get_vm_yaw() { return &(_vm_yaw_val) ; }
	int * get_vm_pitch() { return &(_vm_pitch_val) ; }
	int * get_vm_roll() { return &(_vm_roll_val) ; }

	string * get_vm_clickmsg() { return &(_vm_clickmsg_val) ; }
	int  get_vm_clickmsg_position() { return _vm_clickmsg_position ; }

	//--------------------------------------------------------------------------------
	// The following methods are used by tostring*-type link. All the values above 
	// are written into string and store here
	//--------------------------------------------------------------------------------
	string* get_vm_rx_str() { return &(_vm_rx_str) ;}
	string* get_vm_ry_str() { return &(_vm_ry_str) ; }
	string* get_vm_rz_str() { return &(_vm_rz_str) ; }
	string* get_vm_sizex_str() { return &(_vm_sizex_str) ; }
	string* get_vm_sizey_str() { return &(_vm_sizey_str) ; }
	string* get_vm_sizez_str() { return &(_vm_sizez_str) ; }
	string* get_vm_sizexscale_str() { return &(_vm_sizexscale_str); }
	string* get_vm_sizeyscale_str() { return &(_vm_sizeyscale_str); }
	string* get_vm_sizezscale_str() { return &(_vm_sizezscale_str); }
	string * get_vm_r_str() { return &(_vm_r_str) ; }  
	string * get_vm_g_str() { return &(_vm_g_str) ; }
	string * get_vm_b_str() { return &(_vm_b_str) ; }
	string * get_vm_transparency_str() {return &(_vm_transparency_str) ;}
	string * get_vm_yaw_str() { return &(_vm_yaw_str) ; }
	string * get_vm_pitch_str() { return &(_vm_pitch_str) ; }
	string * get_vm_roll_str() { return &(_vm_roll_str) ; }



	virtual void setColorandTransparency(Ogre::Vector4 v);

	/** when a composite vm tries to propagate a mouse event, it must check
	    if a clicked vm is a sub component of this vm. For example, a 
		container composite vm should answer if a given vm is part of it or not
	*/
	virtual bool isSubComponent(DIVA_VM *vm);


	/** 由於vm_clone mapping node可能會更改vm內部的值
		因此新增這個method加以處理
	*/
	void updateByXpp(xParameterPack xpp);

#if TEST_MODE == TEST_MODE_LOG || TEST_MODE == TEST_MODE_TEST
	// add by ParrotT
	// 列出VM的所有屬性 以便記錄目前的VM狀態
	string ToString();
#endif

protected:
	
	DIVA_VM(xParameterPack xpp);
	DIVA_VM() {};

	
	Ogre::Entity* _ent;  
	Ogre::MovableText* _namemsg ;
	/** If this flag is set to false, new_layout vm such as RegularPointer_layoutvm will not be able to
	    move it. By default, this value is set to true in DIVA_VM constructor*/
	bool _movable ;  
	Ogre::SceneNode*	 _name_scene_node ;

	Ogre::MovableText* _msg ;
	Ogre::SceneNode*   _text_scene_node ; 
	bool _textvisible ;
	bool _prohibit_defaults[10] ;

	vector<bool> _para_onoff ;
	string _name; // the name of the VM
	int _vm_name_position; // which location you want _name to appear off, it can be NORTH, SOUTH, EAST, WEST, FRONT, and BACK

	// 3D positions
	float* _vm_rx;   // the RELATIVE (x,y,z) to its parent scene node
	float* _vm_ry;
	float* _vm_rz;
	float _vm_rx_val ; // the real variables that keep the values obtained from _vm_rx ;
	float _vm_ry_val ; // the real variables that keep the values obtained from _vm_ry ;
	float _vm_rz_val ; // the real variables that keep the values obtained from _vm_rz ;
	string _vm_rx_str ; // the real variables that keep the values obtained from _vm_rx ;
	string _vm_ry_str ; // the real variables that keep the values obtained from _vm_ry ;
	string _vm_rz_str ; // the real variables that keep the values obtained from _vm_rz ;

	// 3D real size
	float* _vm_sizex;
	float* _vm_sizey;
	float* _vm_sizez;
	float _vm_sizex_val; // the real variables that keep the values obtained from _vm_sizex ;
	float _vm_sizey_val;
	float _vm_sizez_val;
	string _vm_sizex_str; // the real variables that keep the values obtained from _vm_sizex ;
	string _vm_sizey_str;
	string _vm_sizez_str;	

	float _vm_init_sizex ;
	float _vm_init_sizey ;
	float _vm_init_sizez ;

	// in normal case, the original mesh is of arbitrary size (let it be _MeshSize)
	// when it is scaled to a real size (let it be _RealSize) , it is actually scale at a factor _RealSize/_MeshSize)
	// these scaling parameter can be linked to double variable as well.

	double* _vm_sizexscale;
	double* _vm_sizeyscale;
	double* _vm_sizezscale;
	double _vm_sizexscale_val;
	double _vm_sizeyscale_val;
	double _vm_sizezscale_val;
	string _vm_sizexscale_str;
	string _vm_sizeyscale_str;
	string _vm_sizezscale_str;

	// the color of the entities in RGB ;
	double * _vm_r ;  
	double * _vm_g ;
	double * _vm_b ;
	double  _vm_r_val ;  
	double  _vm_g_val ;
	double  _vm_b_val ;
	string  _vm_r_str ;  
	string  _vm_g_str ;
	string  _vm_b_str ;

	double * _vm_transparency ; // the degree of transparency of a VM
	double _vm_transparency_val ;
	string _vm_transparency_str ;

	int * _vm_yaw;             
	int * _vm_pitch;
	int * _vm_roll;
	int  _vm_yaw_val;            
	int  _vm_pitch_val;
	int  _vm_roll_val;
	string  _vm_yaw_str;            
	string  _vm_pitch_str;
	string  _vm_roll_str;


	Ogre::Quaternion* _vm_quat ; // for quaternion, please read http://www.ogre3d.org/wiki/index.php/Quaternion_and_Rotation_Primer  
	Ogre::Quaternion _vm_quat_val ;
	string  _vm_quat_str ;

	string * _vm_clickmsg ;
	string _vm_clickmsg_val ;

	int  _vm_clickmsg_position ;

	bool _visible ;



	// the end of basic attributes.
	// --------------------------------------------------------------------------------------------
	// This section contains the virtual functions that all the subclass VM should implement
	void init_default_parameters();

	/** all the subclass should load the 3D resources by themselves */
	virtual void load_3Dresources() { }

	/** register the relation of the entity and vm in diva manager
	   When this entity is clicked, mouse/keyboard VM will be passed to this VM
	   By default it can be only one entity representing this VM */
	virtual void reg_event_entity() { } ;

	/** the following is the methods called by init_default_parameters in order.
	    Each method have a default implementation and can be overridden if necessary.
		You can also turn off some method by setting _prohibut_defaults[] 
		or by calling the skip_xxx() explicitly in init_private_attrs_started()
	*/
	
	virtual void set_default_values()=0;
	virtual void init_private_attrs_started() { };  // this method should be changed to =0 after the all VMs are deleted
	virtual void init_print_name() ;
	virtual void init_position();
	virtual void init_size_and_scale();
	// virtual void init_scale();
	virtual void init_color_and_transparency();
	virtual void init_rotation();
	//virtual void init_transparency() ;
	virtual void init_quaternion();
	virtual void init_clickmsg();
	void         generate_valstring();
	/** replace clickmsg is called in init_clickmsg, VMPicked and VMValueUpdate. 
		This method should replace @1 @2 in the clickmsg to the class specific message.
		See ubvm_2darray for example.
		By default, it does nothing.
	*/
	virtual string replace_clickmsg();
	virtual void init_private_attrs_ended() { } ;

	void skip_init_print_name() { _prohibit_defaults[SKIP_NAME] = true ; }
	void skip_init_position() { _prohibit_defaults[SKIP_POSITION] = true ; }
	void skip_init_size() { _prohibit_defaults[SKIP_SIZE] = true ; }
	void skip_init_scale() { _prohibit_defaults[SKIP_SCALE] = true ; }
	void skip_init_color() { _prohibit_defaults[SKIP_COLOR] = true ; }
	void skip_init_rotation() { _prohibit_defaults[SKIP_ROTATION] = true ; }
	void skip_init_transparency() { _prohibit_defaults[SKIP_TRANS] = true ; }
	void skip_init_quaternion() { _prohibit_defaults[SKIP_QUATERNION] = true ; }
	void skip_init_clickmsg() { _prohibit_defaults[SKIP_CLICKMSG] = true ;}
	


	virtual void update_position();
	virtual void update_size_and_scale();
	//virtual void update_scale();
	virtual void update_color_and_transparency();
	virtual void update_rotation();
	//virtual void update_transparency() ;
	virtual void update_quaternion();
	virtual void update_clickmsg();

	virtual void update_private_attrs_started() { };  // this method should be changed to =0 after the all VMs are deleted
	virtual void update_private_attrs_ended() { } ;

	

	Ogre::Vector3	VL_computeVarnamePosition(const DIVA_VM::TextPosition &textposition) ;
	/** when VM is resized, the variale name should be re-adjusted */
	void VL_updateVarnamePosition() ; 
	// --------------------------------------------------------------------------------------------

	// the following is a set of shared routines that are commonly used by 
	// all the VM
	// These method names all begin with VL

	/**/
	map<Ogre::MovableObject*,DIVA_VM*>* VL_getVMMovableObjectTable(); // hyt 08/10/20
	
	Ogre::Entity* VL_createEntity(string meshname,string materialname = "",string specialhead = "");//hyt 08/10/20	
	void VL_setEntityColor(Ogre::Entity* target,Ogre::Vector4 colorvalue);//hyt 08/10/20
	void VL_regBoundingBox(Ogre::Entity*);//hyt 08/10/20
	void VL_arrangeVMs(vector<DIVA_VM*>);//hyt 08/10/20
	Ogre::Vector3 VL_computeMaxBoundingsize(vector<DIVA_VM*>,const Coordinate_axis&,const Coordinate_axis&,const Coordinate_axis&);//hyt 08/10/20
	Ogre::Vector3 VL_computeMinBoundingsize(vector<DIVA_VM*>,const Coordinate_axis&,const Coordinate_axis&,const Coordinate_axis&);//hyt 08/10/20
	void VL_setVMsPosition(vector<DIVA_VM*>&,Ogre::Vector3,Ogre::SceneNode*); //hyt 08/10/20
	void VL_minimizeVMsize(vector<DIVA_VM*>&,int); //hyt 08/10/20

	Ogre::SceneNode* VL_createTextNode(const TextPosition& textposition ,Ogre::Vector3 position = Ogre::Vector3(0,0,0),std::string specialhead="");//hyt 08/10/20
	Ogre::MovableText* VL_createVMtext(string text,string specialhead = ""); //hyt 08/10/20



	void VL_updateText(Ogre::MovableText* msg,string text); // hyt 08/10/20
	int VL_propagateMouseEvent(vector<DIVA_VM*>,Ogre::Vector3); //hyt 08/10/20
	int VL_propagateDraggedEvent(vector<DIVA_VM*>, Ogre::Vector3 screenpos, Ogre::Vector3 abspos); //hyt 08/10/20
	void VL_addVMAnimation(); //hyt 08/10/26
};

#endif